#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "Class.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class BehavioralFeature;
class BehavioredClassifier;
class Constraint;
class Element;
class Parameter;
class ParameterSet;

/// <summary>
/// Behavior
/// Behavior is a specification of how its context BehavioredClassifier changes
/// state over time. This specification may be either a definition of possible
/// behavior execution or emergent behavior, or a selective illustration of an
/// interesting subset of possible executions. The latter form is typically used for
/// capturing examples, such as a trace of a particular execution.
/// </summary>
class UMLMODEL_EXPORT Behavior : public Class {

public: // Constructors and destructors
    explicit Behavior(const QString& umlType="uml::Behavior");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// behavioredClassifier
    /// The first BehavioredClassifier reached by following the chain of owner
    /// relationships from the Behavior, if any.
    /// </summary>
    virtual shared_ptr<BehavioredClassifier> behavioredClassifier(shared_ptr<Element> from) const;

    /// <summary>
    /// inputParameters
    /// The in and inout ownedParameters of the Behavior.
    /// </summary>
    virtual shared_ptr<vector<Parameter>> inputParameters() const;

    /// <summary>
    /// outputParameters
    /// The out, inout and return ownedParameters.
    /// </summary>
    virtual shared_ptr<vector<Parameter>> outputParameters() const;

public: // Properties
    /// <summary>
    /// context getter
    /// The BehavioredClassifier that is the context for the execution of the Behavior.
    /// A Behavior that is directly owned as a nestedClassifier does not have a context.
    /// Otherwise, to determine the context of a Behavior, find the first
    /// BehavioredClassifier reached by following the chain of owner relationships from
    /// the Behavior, if any. If there is such a BehavioredClassifier, then it is the
    /// context, unless it is itself a Behavior with a non-empty context, in which case
    /// that is also the context for the original Behavior. For example, following this
    /// algorithm, the context of an entry Behavior in a StateMachine is the
    /// BehavioredClassifier that owns the StateMachine. The features of the context
    /// BehavioredClassifier as well as the Elements visible to the context Classifier
    /// are visible to the Behavior.
    /// </summary>
    shared_ptr<BehavioredClassifier> context() const;

    /// <summary>
    /// context setter
    /// The BehavioredClassifier that is the context for the execution of the Behavior.
    /// A Behavior that is directly owned as a nestedClassifier does not have a context.
    /// Otherwise, to determine the context of a Behavior, find the first
    /// BehavioredClassifier reached by following the chain of owner relationships from
    /// the Behavior, if any. If there is such a BehavioredClassifier, then it is the
    /// context, unless it is itself a Behavior with a non-empty context, in which case
    /// that is also the context for the original Behavior. For example, following this
    /// algorithm, the context of an entry Behavior in a StateMachine is the
    /// BehavioredClassifier that owns the StateMachine. The features of the context
    /// BehavioredClassifier as well as the Elements visible to the context Classifier
    /// are visible to the Behavior.
    /// </summary>
    void setContext(shared_ptr<BehavioredClassifier> value);

    /// <summary>
    /// isReentrant getter
    /// Tells whether the Behavior can be invoked while it is still executing from a
    /// previous invocation.
    /// </summary>
    bool isReentrant() const;

    /// <summary>
    /// isReentrant setter
    /// Tells whether the Behavior can be invoked while it is still executing from a
    /// previous invocation.
    /// </summary>
    void setIsReentrant(bool value);

    /// <summary>
    /// ownedParameters getter
    /// References a list of Parameters to the Behavior which describes the order and
    /// type of arguments that can be given when the Behavior is invoked and of the
    /// values which will be returned when the Behavior completes its execution.
    /// </summary>
    vector<shared_ptr<Parameter>>& ownedParameters();

    /// <summary>
    /// ownedParameterSets getter
    /// The ParameterSets owned by this Behavior.
    /// </summary>
    vector<shared_ptr<ParameterSet>>& ownedParameterSets();

    /// <summary>
    /// postconditions getter
    /// An optional set of Constraints specifying what is fulfilled after the execution
    /// of the Behavior is completed, if its precondition was fulfilled before its
    /// invocation.
    /// </summary>
    vector<shared_ptr<Constraint>>& postconditions();

    /// <summary>
    /// preconditions getter
    /// An optional set of Constraints specifying what must be fulfilled before the
    /// Behavior is invoked.
    /// </summary>
    vector<shared_ptr<Constraint>>& preconditions();

    /// <summary>
    /// specification getter
    /// Designates a BehavioralFeature that the Behavior implements. The
    /// BehavioralFeature must be owned by the BehavioredClassifier that owns the
    /// Behavior or be inherited by it. The Parameters of the BehavioralFeature and the
    /// implementing Behavior must match. A Behavior does not need to have a
    /// specification, in which case it either is the classifierBehavior of a
    /// BehavioredClassifier or it can only be invoked by another Behavior of the
    /// Classifier.
    /// </summary>
    shared_ptr<BehavioralFeature> specification() const;

    /// <summary>
    /// specification setter
    /// Designates a BehavioralFeature that the Behavior implements. The
    /// BehavioralFeature must be owned by the BehavioredClassifier that owns the
    /// Behavior or be inherited by it. The Parameters of the BehavioralFeature and the
    /// implementing Behavior must match. A Behavior does not need to have a
    /// specification, in which case it either is the classifierBehavior of a
    /// BehavioredClassifier or it can only be invoked by another Behavior of the
    /// Classifier.
    /// </summary>
    void setSpecification(shared_ptr<BehavioralFeature> value);

    /// <summary>
    /// redefinedBehaviors getter
    /// References the Behavior that this Behavior redefines. A subtype of Behavior may
    /// redefine any other subtype of Behavior. If the Behavior implements a
    /// BehavioralFeature, it replaces the redefined Behavior. If the Behavior is a
    /// classifierBehavior, it extends the redefined Behavior.
    /// </summary>
    vector<shared_ptr<Behavior>>& redefinedBehaviors();

private: // Fields
    /// <summary>
    /// context
    /// The BehavioredClassifier that is the context for the execution of the Behavior.
    /// A Behavior that is directly owned as a nestedClassifier does not have a context.
    /// Otherwise, to determine the context of a Behavior, find the first
    /// BehavioredClassifier reached by following the chain of owner relationships from
    /// the Behavior, if any. If there is such a BehavioredClassifier, then it is the
    /// context, unless it is itself a Behavior with a non-empty context, in which case
    /// that is also the context for the original Behavior. For example, following this
    /// algorithm, the context of an entry Behavior in a StateMachine is the
    /// BehavioredClassifier that owns the StateMachine. The features of the context
    /// BehavioredClassifier as well as the Elements visible to the context Classifier
    /// are visible to the Behavior.
    /// </summary>
    shared_ptr<BehavioredClassifier> context_;

    /// <summary>
    /// isReentrant
    /// Tells whether the Behavior can be invoked while it is still executing from a
    /// previous invocation.
    /// </summary>
    const static bool isReentrant_default_;
    bool isReentrant_= isReentrant_default_;

    /// <summary>
    /// ownedParameters
    /// References a list of Parameters to the Behavior which describes the order and
    /// type of arguments that can be given when the Behavior is invoked and of the
    /// values which will be returned when the Behavior completes its execution.
    /// </summary>
    vector<shared_ptr<Parameter>> ownedParameters_;

    /// <summary>
    /// ownedParameterSets
    /// The ParameterSets owned by this Behavior.
    /// </summary>
    vector<shared_ptr<ParameterSet>> ownedParameterSets_;

    /// <summary>
    /// postconditions
    /// An optional set of Constraints specifying what is fulfilled after the execution
    /// of the Behavior is completed, if its precondition was fulfilled before its
    /// invocation.
    /// </summary>
    vector<shared_ptr<Constraint>> postconditions_;

    /// <summary>
    /// preconditions
    /// An optional set of Constraints specifying what must be fulfilled before the
    /// Behavior is invoked.
    /// </summary>
    vector<shared_ptr<Constraint>> preconditions_;

    /// <summary>
    /// specification
    /// Designates a BehavioralFeature that the Behavior implements. The
    /// BehavioralFeature must be owned by the BehavioredClassifier that owns the
    /// Behavior or be inherited by it. The Parameters of the BehavioralFeature and the
    /// implementing Behavior must match. A Behavior does not need to have a
    /// specification, in which case it either is the classifierBehavior of a
    /// BehavioredClassifier or it can only be invoked by another Behavior of the
    /// Classifier.
    /// </summary>
    shared_ptr<BehavioralFeature> specification_;

    /// <summary>
    /// redefinedBehaviors
    /// References the Behavior that this Behavior redefines. A subtype of Behavior may
    /// redefine any other subtype of Behavior. If the Behavior implements a
    /// BehavioralFeature, it replaces the redefined Behavior. If the Behavior is a
    /// classifierBehavior, it extends the redefined Behavior.
    /// </summary>
    vector<shared_ptr<Behavior>> redefinedBehaviors_;

};

} // namespace uml
